/******************************************************************************
 * Copyright 2013-2014 Espressif Systems (Wuxi)
 *
 * FileName: user_main.c
 *
 * Description: entry file of user application
 *
 * Modification history:
 *     2015/1/23, v1.0 create this file.
 *******************************************************************************/

#include "osapi.h"
#include "at_custom.h"
#include "user_interface.h"
#include "smartconfig.h"
#include "espconn.h"
#include "mem.h"
#include "driver/uart.h"

#define SSID "Xiaomi_C38e"
#define PASSWORD "yanhua-2017"
#define NET_DOMAIN "cn.bing.com"
#define pheadbuffer "GET / HTTP/1.1\r\nUser-Agent: curl/7.37.0\r\nHost: %s\r\nAccept: */*\r\n\r\n"
LOCAL struct espconn user_tcp_conn;
#define packet_size   (2 * 1024)
LOCAL os_timer_t connect_timer;

void ICACHE_FLASH_ATTR
user_send_data(struct espconn *pespconn) {
	char *pbuf = (char *) os_zalloc(packet_size);

	os_sprintf(pbuf, pheadbuffer, NET_DOMAIN);

	espconn_send(pespconn, pbuf, os_strlen(pbuf));

	os_free(pbuf);

}

void ICACHE_FLASH_ATTR
user_tcp_recv_cb(void *arg, char *pusrdata, unsigned short length) {
	//received some data from tcp connection

	at_port_print("Received data string:");
	at_port_print(pusrdata);

}

void ICACHE_FLASH_ATTR
user_tcp_sent_cb(void *arg) {
	//data sent successfully

	at_port_print("Sent callback: data sent successfully.\r\n");
	at_port_print("user_tcp_sent_cb");
}

void ICACHE_FLASH_ATTR
user_tcp_discon_cb(void *arg) {
	//tcp disconnect successfully
	at_port_print("user_tcp_discon_cb");
	at_port_print("Disconnected from server.\r\n");
}

void ICACHE_FLASH_ATTR
user_tcp_connect_cb(void *arg) {
	struct espconn *pespconn = arg;

	at_port_print("Connected to server...\r\n");

	espconn_regist_recvcb(pespconn, user_tcp_recv_cb);
	espconn_regist_sentcb(pespconn, user_tcp_sent_cb);
	espconn_regist_disconcb(pespconn, user_tcp_discon_cb);

	user_send_data(pespconn);
}

void ICACHE_FLASH_ATTR
user_tcp_recon_cb(void *arg, sint8 err) {
	//error occured , tcp connection broke. user can try to reconnect here.

	os_printf("Reconnect callback called, error code: %d !!! \r\n", err);
	at_port_print("user_tcp_recon_cb");
}

void tcp_client_init(void) {
	at_port_print("tcp_client_init");

	// Connect to tcp server as NET_DOMAIN
	user_tcp_conn.proto.tcp = (esp_tcp *) os_zalloc(sizeof(esp_tcp));
	user_tcp_conn.type = ESPCONN_TCP;
	user_tcp_conn.state = ESPCONN_NONE;
	const char esp_tcp_server_ip[4] = { 192, 168, 31, 33 }; // remote IP of TCP server

	os_memcpy(user_tcp_conn.proto.tcp->remote_ip, esp_tcp_server_ip, 4);

	user_tcp_conn.proto.tcp->remote_port = 9999;  // remote port

	user_tcp_conn.proto.tcp->local_port = espconn_port(); //local port of ESP8266

	espconn_regist_connectcb(&user_tcp_conn, user_tcp_connect_cb); // register connect callback
	espconn_regist_reconcb(&user_tcp_conn, user_tcp_recon_cb); // register reconnect callback as error handler
	espconn_connect(&user_tcp_conn);
}

void ICACHE_FLASH_ATTR
at_setupCmdRestore(uint8_t id, char *pPara) {
	uint8 buffer[32] = { 0 };

	os_sprintf(buffer, "%s\r\n", "at_setupCmdRestore");
	at_port_print(buffer);
	at_response_ok();
}

void ICACHE_FLASH_ATTR
at_testCmdRestore(uint8_t id) {
	uint8 buffer[32] = { 0 };

	os_sprintf(buffer, "%s\r\n", "at_testCmdRestore");
	at_port_print(buffer);
	at_response_ok();
}

void ICACHE_FLASH_ATTR
at_queryCmdRestore(uint8_t id) {
	uint8 buffer[32] = { 0 };

	os_sprintf(buffer, "%s\r\n", "at_queryCmdRestore");
	at_port_print(buffer);
	at_response_ok();
}

void ICACHE_FLASH_ATTR
at_exeCmdRestore(uint8_t id) {

	uint8 buffer[32] = { 0 };
	os_sprintf(buffer, "%s\r\n", "at_exeCmdRestore");
	at_port_print(buffer);
	at_response_ok();
	system_restore();
	system_restart();

}

// test :AT+TEST=1,"abc"<,3>
void ICACHE_FLASH_ATTR
at_setupCmdTest(uint8_t id, char *pPara) {
	int result = 0, err = 0, flag = 0;
	uint8 buffer[32] = { 0 };
	pPara++; // skip '='

	//get the first parameter
	// digit
	flag = at_get_next_int_dec(&pPara, &result, &err);

	// flag must be ture because there are more parameter
	if (flag == FALSE) {
		at_response_error();
		return;
	}

	if (*pPara++ != ',') { // skip ','
		at_response_error();
		return;
	}

	os_sprintf(buffer, "the first parameter:%d\r\n", result);
	at_port_print(buffer);

	//get the second parameter
	// string
	at_data_str_copy(buffer, &pPara, 10);
	at_port_print("the second parameter:");
	at_port_print(buffer);
	at_port_print("\r\n");

	if (*pPara == ',') {
		pPara++; // skip ','
		result = 0;
		//there is the third parameter
		// digit
		flag = at_get_next_int_dec(&pPara, &result, &err);
		// we donot care of flag
		os_sprintf(buffer, "the third parameter:%d\r\n", result);
		at_port_print(buffer);
	}

	if (*pPara != '\r') {
		at_response_error();
		return;
	}

	at_response_ok();
}

void ICACHE_FLASH_ATTR
at_testCmdTest(uint8_t id) {
	uint8 buffer[32] = { 0 };

	os_sprintf(buffer, "%s\r\n", "at_testCmdTest");
	at_port_print(buffer);
	at_response_ok();
}

void ICACHE_FLASH_ATTR
at_queryCmdTest(uint8_t id) {
	uint8 buffer[32] = { 0 };

	os_sprintf(buffer, "%s\r\n", "at_queryCmdTest");
	at_port_print(buffer);
	at_response_ok();
}

void ICACHE_FLASH_ATTR
at_exeCmdTest(uint8_t id) {
	uint8 buffer[32] = { 0 };

	os_sprintf(buffer, "%s\r\n", "at_exeCmdTest");
	at_port_print(buffer);
	at_response_ok();
}

extern void at_exeCmdCiupdate(uint8_t id);
at_funcationType at_custom_cmd[] = { { "+TEST", 5, at_testCmdTest,
		at_queryCmdTest, at_setupCmdTest, at_exeCmdTest },

{ "+LHRESTORE", 10, at_testCmdRestore, at_queryCmdRestore, at_setupCmdRestore,
		at_exeCmdRestore },

#ifdef AT_UPGRADE_SUPPORT
		{	"+CIUPDATE", 9, NULL, NULL, NULL, at_exeCmdCiupdate}
#endif
	};

void tcp_heartBit(void) {
	//at_port_print("\r\n tcp_heartBit \r\n");
}

void tcp_heartBit_init(void) {
	LOCAL os_timer_t ip_timer;
	os_timer_disarm(&ip_timer);
	os_timer_setfn(&ip_timer, (os_timer_func_t *) tcp_heartBit, NULL);
	os_timer_arm(&ip_timer, 5000, 1);
}

void tcp_connect_init(void) {

}

void user_rf_pre_init(void) {
}

void ICACHE_FLASH_ATTR Wifi_conned(void *arg) {

	at_port_print("\r\n check_wifi_connect \r\n");
	static uint8 count = 0;
	uint8 status;
	os_timer_disarm(&connect_timer);
	count++;
	status = wifi_station_get_connect_status();
	if (status == STATION_GOT_IP) {

		at_port_print("STATION_GOT_IP");
		tcp_client_init();
		os_timer_disarm(&connect_timer);
		return;
	} else {
		switch (status) {
		case STATION_CONNECTING:
			at_port_print("STATION_CONNECTING");
			break;

		case STATION_WRONG_PASSWORD:
			at_port_print("STATION_WRONG_PASSWORD");
			break;

		case STATION_NO_AP_FOUND:
			at_port_print("STATION_NO_AP_FOUND");
			break;

		case STATION_CONNECT_FAIL:
			at_port_print("STATION_CONNECT_FAIL");
			break;
		default:
			break;
		}

		if (count >= 7) {
			at_port_print("Wifi connect fail！");
			return;
		} else {
//
		}

	}

	os_timer_arm(&connect_timer, 2000, NULL);

}

void ICACHE_FLASH_ATTR
user_set_station_config(void) {

	at_port_print("\r\n wifi_set_opmode \r\n");
	bool modeset = wifi_set_opmode(STATION_MODE);

	if (modeset != 0) {
		at_port_print("\r\n wifi_set_opmode yes \r\n");
	} else {
		at_port_print("\r\n wifi_set_opmode no \r\n");
	}

	char ssid[32] = SSID;
	char password[64] = PASSWORD;
	struct station_config stationConf;
	stationConf.bssid_set = 0;		//need	not	check	MAC	address	of	AP
	os_memcpy(&stationConf.ssid, ssid, 32);
	os_memcpy(&stationConf.password, password, 64);
	wifi_station_set_config(&stationConf);

	os_timer_setfn(&connect_timer, Wifi_conned, NULL);		//调用自己写的WiFi连接函数
	os_timer_arm(&connect_timer, 2000, NULL);		//设置连接WiFi定时器
}

void user_at_init(void) {
	char buf[64] = { 0 };
	at_customLinkMax = 5;
	//os_sprintf(buf,"compile time:%s %s",__DATE__,__TIME__);
	at_set_custom_info(buf);
	//at_port_print("\r\nready\r\n");
	at_cmd_array_regist(&at_custom_cmd[0],
			sizeof(at_custom_cmd) / sizeof(at_custom_cmd[0]));
}

void ICACHE_FLASH_ATTR
smartconfig_done2(sc_status status, void *pdata) {
	switch (status) {
	case SC_STATUS_WAIT:
		at_port_print("SC_STATUS_WAIT\n");
		break;
	case SC_STATUS_FIND_CHANNEL:
		at_port_print("SC_STATUS_FIND_CHANNEL\n");
		break;
	case SC_STATUS_GETTING_SSID_PSWD:
		at_port_print("SC_STATUS_GETTING_SSID_PSWD\n");
		sc_type *type = pdata;
		if (*type == SC_TYPE_ESPTOUCH) {
			at_port_print("SC_TYPE:SC_TYPE_ESPTOUCH\n");
		} else {
			at_port_print("SC_TYPE:SC_TYPE_AIRKISS\n");
		}
		break;
	case SC_STATUS_LINK:
		at_port_print("SC_STATUS_LINK\n");
		struct station_config *sta_conf = pdata;
		wifi_station_set_config(sta_conf);
		wifi_station_disconnect();
		wifi_station_connect();
		break;
	case SC_STATUS_LINK_OVER:
		at_port_print("SC_STATUS_LINK_OVER\n");
		if (pdata != NULL) {
			uint8 phone_ip[4] = { 0 };
			memcpy(phone_ip, (uint8*) pdata, 4);
			os_printf("Phone	IP:	%d.%d.%d.%d\n", phone_ip[0], phone_ip[1],
					phone_ip[2], phone_ip[3]);
		}

		smartconfig_stop();

		os_timer_disarm(&connect_timer);
		os_timer_setfn(&connect_timer, Wifi_conned, NULL);		//调用自己写的WiFi连接函数
		os_timer_arm(&connect_timer, 2000, NULL);		//设置连接WiFi定时器

		break;
	}
}

void ICACHE_FLASH_ATTR
user_start_smartconfig(void) {
	bool modeset = wifi_set_opmode(STATION_MODE);
	if (modeset != 0) {
		at_port_print("\r\n wifi_set_opmode yes \r\n");
		smartconfig_start(smartconfig_done2);
		at_port_print("no WIFI cache \r\n");
	} else {
		at_port_print("\r\n wifi_set_opmode no \r\n");
	}
}

void user_init(void) {

//1.开启at功能
//2.尝试连接wifi，若wifi连接失败的话开启smartconfig


	//os_sprintf("\r\n uart init \r\n");

	at_init(); //初始化AT指令
	user_at_init();
	uart_init(BIT_RATE_9600,BIT_RATE_9600);//串口波特率修改

	 struct station_config s_staconf;
	 wifi_station_get_config(&s_staconf);
	 if (os_strlen(s_staconf.ssid) != 0) {
	 //存在wifi相关配置信息，直接连接wifi
	 at_port_print("has WIFI cache \r\n");
	 wifi_station_connect();
	 os_timer_disarm(&connect_timer);
	 os_timer_setfn(&connect_timer, Wifi_conned, NULL);		//调用自己写的WiFi连接函数
	 os_timer_arm(&connect_timer, 2000, NULL);		//设置连接WiFi定时器

	 } else {
	 //如果不存在，开启快速配网模式
	 user_start_smartconfig();
	 }




	at_port_print("\r\n user_init \r\n");
}

